package me.tonywang.quartz.service;

import com.baomidou.mybatisplus.toolkit.IdWorker;
import me.tonywang.quartz.CronTaskFactoryBean;
import me.tonywang.quartz.QuartzUtils;
import me.tonywang.quartz.entity.Crontask;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.MethodInvoker;
import org.springframework.util.StringUtils;

import java.text.ParseException;
import java.util.List;

/**
 * @className: CrontabTaskService
 * @description:
 * @author: WANGHUI
 * @createDate: 2018/5/15 15:58
 * @version: 1.0
 */
@Service
public class CrontabTaskService implements ApplicationContextAware  {


    Logger logger = LoggerFactory.getLogger(getClass());


    @Autowired
    Scheduler scheduler;


    public void saveJob(Crontask task) throws BeansException, ParseException, SchedulerException {
        CronTaskFactoryBean cronTaskFactoryBean = new CronTaskFactoryBean();
        cronTaskFactoryBean.setName(task.getJobName());
        cronTaskFactoryBean.setGroup(task.getJobGroup());
        cronTaskFactoryBean.setCronExpression(task.getCronExpression());
        cronTaskFactoryBean.setTargetBeanName(task.getTargetBeanName());
        cronTaskFactoryBean.setTargetMethod(task.getTargetMethod());
        cronTaskFactoryBean.setRequestObj(task.getRequestObj());
        cronTaskFactoryBean.setConcurrent("1".equals(task.getConcurrent()));
//        cronTaskFactoryBean.setMisfireInstruction(task.getMisfire() == null ? MISFIRE_INSTRUCTION_DO_NOTHING : task.getMisfire());
        cronTaskFactoryBean.setPriority(task.getPriority() == null ? 0 : task.getPriority());
        //手动执行的任务
        if (!StringUtils.hasText(task.getCronExpression())) {
            cronTaskFactoryBean.setDurability(true);
            scheduler.addJob(cronTaskFactoryBean.getJobDetail(), true, true);
        } else {
            Trigger trigger = cronTaskFactoryBean.getCronTrigger();
            QuartzUtils.addTriggerToScheduler(scheduler, trigger);
        }
    }

    public void updateJob(Crontask task) throws BeansException, ParseException, SchedulerException {
        CronTaskFactoryBean cronTaskFactoryBean = new CronTaskFactoryBean();
        cronTaskFactoryBean.setName(task.getJobName());
        cronTaskFactoryBean.setGroup(task.getJobGroup());
        cronTaskFactoryBean.setTargetBeanName(task.getTargetBeanName());
        cronTaskFactoryBean.setTargetMethod(task.getTargetMethod());
        cronTaskFactoryBean.setRequestObj(task.getRequestObj());
        cronTaskFactoryBean.setCronExpression(task.getCronExpression());
        cronTaskFactoryBean.setConcurrent("1".equals(task.getConcurrent()));
//        cronTaskFactoryBean.setMisfireInstruction(task.getMisfire() == null ? MISFIRE_INSTRUCTION_DO_NOTHING : task.getMisfire());
        cronTaskFactoryBean.setPriority(task.getPriority() == null ? 0 : task.getPriority());

        //手动执行的任务
        if (!StringUtils.hasText(task.getCronExpression())) {
            cronTaskFactoryBean.setDurability(true);
            scheduler.addJob(cronTaskFactoryBean.getJobDetail(), true, true);
        } else {
            Trigger trigger = cronTaskFactoryBean.getCronTrigger();
            QuartzUtils.updateTriggerToScheduler(scheduler, trigger);
        }
    }

    public void triggerJob(Crontask task) throws BeansException, SchedulerException {
        QuartzUtils.triggerJob(scheduler, new JobKey(task.getJobName(), task.getJobGroup()));
    }

    public void triggerTempJob(Crontask task) throws BeansException, SchedulerException {
        triggerTempJob(task, 0);
    }


    public void triggerTempJob(Crontask task, int startupDelay) throws BeansException, SchedulerException {
        CronTaskFactoryBean cronTaskFactoryBean = new CronTaskFactoryBean();
        cronTaskFactoryBean.setName(task.getJobName() == null ? IdWorker.get32UUID() : task.getJobName());
        cronTaskFactoryBean.setGroup("TEMP");
        cronTaskFactoryBean.setTargetBeanName(task.getTargetBeanName());
        cronTaskFactoryBean.setTargetMethod(task.getTargetMethod());
        cronTaskFactoryBean.setRequestObj(task.getRequestObj());
        if (startupDelay > 0)
            QuartzUtils.triggerTempJob(scheduler, cronTaskFactoryBean.getJobDetail(), startupDelay);
        else
            QuartzUtils.triggerTempJob(scheduler, cronTaskFactoryBean.getJobDetail());
    }

    public void deleteJob(String jobName, String jobGroup) throws BeansException, SchedulerException {
        QuartzUtils.deleteJob(scheduler, new JobKey(jobName, jobGroup));
    }

    public void deleteJobsInGroup(String groupName) throws BeansException, SchedulerException {
        QuartzUtils.deleteJobs(scheduler, groupName);
    }

    public void pauseJob(String jobName, String jobGroup) throws BeansException, SchedulerException {
        QuartzUtils.pauseJob(scheduler, new JobKey(jobName, jobGroup));
    }

    public void pauseJobsInGroup(String groupName) throws BeansException, SchedulerException {
        QuartzUtils.pauseJobs(scheduler, groupName);
    }

    public void pauseAllJob() throws BeansException, SchedulerException {
        QuartzUtils.pauseAll(scheduler);
    }

    public void resumeJob(String jobName, String jobGroup) throws BeansException, SchedulerException {
        QuartzUtils.resumeJob(scheduler, new JobKey(jobName, jobGroup));
    }

    public void resumeJobsInGroup(String jobGroup) throws BeansException, SchedulerException {
        QuartzUtils.resumeJobs(scheduler, jobGroup);
    }

    public void resumeAllJob() throws BeansException, SchedulerException {
        QuartzUtils.resumeAll(scheduler);
    }

    public SchedulerMetaData getMetaData() throws BeansException, SchedulerException {
        return QuartzUtils.getMetaData(scheduler);
    }

    public List<JobExecutionContext> getCurrentlyExecutingJobs() throws BeansException, SchedulerException {
        return QuartzUtils.getCurrentlyExecutingJobs(scheduler);
    }

    private ApplicationContext ctx;

    private void prepareMethodInvoker(Crontask task) throws ClassNotFoundException, NoSuchMethodException {
        MethodInvoker invoker = new MethodInvoker();
        Assert.state(ctx != null, "BeanFactory must be set when using 'targetBeanName'");
        invoker.setTargetClass(this.ctx.getType(task.getTargetBeanName()));
        invoker.setTargetObject(ctx.getBean(task.getTargetBeanName()));
        invoker.setTargetMethod(task.getTargetMethod());
        if (StringUtils.hasText(task.getRequestObj()))
            invoker.setArguments(task.getRequestObj());
        invoker.prepare();
    }

    public void checkJobConfig( Crontask task) throws ParseException, NoSuchMethodException, ClassNotFoundException {
        if(StringUtils.hasText(task.getCronExpression()))
            QuartzUtils.validateExpression(task.getCronExpression());
        prepareMethodInvoker(task) ;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ctx = applicationContext;
    }
}
